import { eventBus, type ComponentOptions, nextKey, useEventBus } from '@/widgets'
import { markRaw, shallowRef } from 'vue'

type Anchor = {
  top?: number
  right?: number
  bottom?: number
  left?: number
}

export interface AnchorComponent {
  component: Required<ComponentOptions>
  anchor: Anchor
}

interface PositionStyle {
  position: 'absolute'
  left?: string
  right?: string
  top?: string
  bottom?: string
}

function positionStyle(anchor: Anchor): PositionStyle {
  const ret: PositionStyle = {
    position: 'absolute'
  }
  if (anchor.left != null) {
    ret.left = anchor.left + 'px'
  }
  if (anchor.right != null) {
    ret.right = anchor.right + 'px'
  }
  if (anchor.bottom != null) {
    ret.bottom = anchor.bottom + 'px'
  }
  if (anchor.top != null) {
    ret.top = anchor.top + 'px'
  }
  return ret
}

interface StyleComponent {
  component: Required<ComponentOptions>
  position: PositionStyle
}

const addComponentEvent = Symbol('add-component')
type AddComponentEvent = {
  component: ComponentOptions
  position: Anchor | 'left' | 'right'
}

export function addAppComponent(component: ComponentOptions, position: Anchor | 'left' | 'right') {
  eventBus.emit(addComponentEvent, { component, position })
}

function fix(opts: ComponentOptions): Required<ComponentOptions> {
  return {
    component: markRaw(opts.component),
    key: opts.key || nextKey(),
    props: opts.props || {},
    events: Object.assign({}, opts.events)
  }
}

export function useAppComponents() {
  const left = shallowRef<Required<ComponentOptions>[]>([])
  const main = shallowRef<StyleComponent[]>([])
  const right = shallowRef<Required<ComponentOptions>[]>([])
  useEventBus(addComponentEvent, (evt: AddComponentEvent) => {
    const { component, position } = evt
    if (position === 'left') {
      left.value = [...left.value, fix(component)]
    } else if (position === 'right') {
      right.value = [...right.value, fix(component)]
    } else {
      const opts = { component: fix(component), position: positionStyle(position) }
      main.value = [...main.value, opts]
    }
  })
  return { left, main, right }
}
